const { File, User } = require('../models')
const { client, SUPPORTED_FILE_TYPES, MAX_FILE_SIZE, generateFileName, getFilePath } = require('../config/oss')
const fileProcessingService = require('./fileProcessingService')
const logger = require('../utils/logger')
const path = require('path')
const fs = require('fs')

class FileService {
  /**
   * 上传文件到OSS
   * @param {number} userId - 用户ID
   * @param {Object} file - multer文件对象
   * @returns {Promise<Object>} 文件记录
   */
  async uploadFile(userId, file) {
    try {
      // 验证文件类型
      if (!SUPPORTED_FILE_TYPES[file.mimetype]) {
        throw new Error('不支持的文件类型')
      }

      // 验证文件大小
      if (file.size > MAX_FILE_SIZE) {
        throw new Error('文件大小超过限制(50MB)')
      }

      // 生成文件名和路径
      const fileName = generateFileName(file.originalname)
      const filePath = getFilePath(userId, fileName)
      const fileExtension = path.extname(file.originalname).toLowerCase()

      // 上传到OSS
      const result = await client.put(filePath, file.buffer, {
        headers: {
          'Content-Type': file.mimetype,
          'Cache-Control': 'public, max-age=31536000'
        }
      })

      // 获取文件URL
      const fileUrl = result.url || `https://${client.options.bucket}.${client.options.region}.aliyuncs.com/${filePath}`

      // 保存文件记录到数据库
      const fileRecord = await File.create({
        user_id: userId,
        original_name: file.originalname,
        file_name: fileName,
        file_path: filePath,
        file_size: file.size,
        file_type: file.mimetype,
        file_extension: fileExtension,
        file_url: fileUrl,
        status: 1
      })

      // 异步处理文件（生成预览图、提取信息等）
      this.processFileAsync(fileRecord, file.buffer)

      logger.info(`File uploaded successfully: ${filePath}`, { userId, fileId: fileRecord.id })

      return {
        id: fileRecord.id,
        originalName: fileRecord.original_name,
        fileName: fileRecord.file_name,
        fileSize: fileRecord.file_size,
        fileType: fileRecord.file_type,
        fileExtension: fileRecord.file_extension,
        fileUrl: fileRecord.file_url,
        previewUrl: fileRecord.preview_url,
        pageCount: fileRecord.page_count,
        createdAt: fileRecord.created_at
      }
    } catch (error) {
      logger.error('File upload failed:', error)
      throw error
    }
  }

  /**
   * 获取文件信息
   * @param {number} fileId - 文件ID
   * @param {number} userId - 用户ID (可选，用于权限验证)
   * @returns {Promise<Object>} 文件信息
   */
  async getFileById(fileId, userId = null) {
    try {
      const whereClause = { id: fileId, status: 1 }
      if (userId) {
        whereClause.user_id = userId
      }

      const file = await File.findOne({
        where: whereClause,
        include: [
          {
            model: User,
            as: 'user',
            attributes: ['id', 'nickname', 'phone']
          }
        ]
      })

      if (!file) {
        throw new Error('文件不存在')
      }

      return {
        id: file.id,
        userId: file.user_id,
        originalName: file.original_name,
        fileName: file.file_name,
        filePath: file.file_path,
        fileSize: file.file_size,
        fileType: file.file_type,
        fileExtension: file.file_extension,
        fileUrl: file.file_url,
        previewUrl: file.preview_url,
        pageCount: file.page_count,
        status: file.status,
        createdAt: file.created_at,
        updatedAt: file.updated_at,
        user: file.user
      }
    } catch (error) {
      logger.error('Get file failed:', error)
      throw error
    }
  }

  /**
   * 获取用户文件列表
   * @param {number} userId - 用户ID
   * @param {number} page - 页码
   * @param {number} limit - 每页数量
   * @returns {Promise<Object>} 文件列表
   */
  async getUserFiles(userId, page = 1, limit = 20) {
    try {
      const offset = (page - 1) * limit

      const { count, rows } = await File.findAndCountAll({
        where: {
          user_id: userId,
          status: 1
        },
        order: [['created_at', 'DESC']],
        limit,
        offset
      })

      const files = rows.map(file => ({
        id: file.id,
        originalName: file.original_name,
        fileName: file.file_name,
        fileSize: file.file_size,
        fileType: file.file_type,
        fileExtension: file.file_extension,
        fileUrl: file.file_url,
        previewUrl: file.preview_url,
        pageCount: file.page_count,
        createdAt: file.created_at
      }))

      return {
        files,
        pagination: {
          total: count,
          page,
          limit,
          pages: Math.ceil(count / limit)
        }
      }
    } catch (error) {
      logger.error('Get user files failed:', error)
      throw error
    }
  }

  /**
   * 删除文件
   * @param {number} fileId - 文件ID
   * @param {number} userId - 用户ID
   * @returns {Promise<boolean>} 删除结果
   */
  async deleteFile(fileId, userId) {
    try {
      const file = await File.findOne({
        where: {
          id: fileId,
          user_id: userId,
          status: 1
        }
      })

      if (!file) {
        throw new Error('文件不存在')
      }

      // 软删除文件记录
      await file.update({ status: 0 })

      // 从OSS删除文件 (可选，也可以保留用于数据恢复)
      try {
        await client.delete(file.file_path)
        logger.info(`File deleted from OSS: ${file.file_path}`)
      } catch (ossError) {
        logger.warn(`Failed to delete file from OSS: ${file.file_path}`, ossError)
      }

      logger.info(`File deleted successfully: ${fileId}`, { userId })
      return true
    } catch (error) {
      logger.error('Delete file failed:', error)
      throw error
    }
  }

  /**
   * 生成文件下载链接
   * @param {number} fileId - 文件ID
   * @param {number} userId - 用户ID
   * @param {number} expires - 过期时间(秒)
   * @returns {Promise<string>} 下载链接
   */
  async getDownloadUrl(fileId, userId, expires = 3600) {
    try {
      const file = await this.getFileById(fileId, userId)
      
      // 生成签名URL
      const url = client.signatureUrl(file.filePath, {
        expires,
        method: 'GET',
        'response-content-disposition': `attachment; filename="${encodeURIComponent(file.originalName)}"`
      })

      return url
    } catch (error) {
      logger.error('Generate download URL failed:', error)
      throw error
    }
  }

  /**
   * 批量删除过期文件
   * @param {number} days - 过期天数
   * @returns {Promise<number>} 删除数量
   */
  async cleanupExpiredFiles(days = 30) {
    try {
      const expireDate = new Date()
      expireDate.setDate(expireDate.getDate() - days)

      const expiredFiles = await File.findAll({
        where: {
          status: 0,
          updated_at: {
            [require('sequelize').Op.lt]: expireDate
          }
        }
      })

      let deletedCount = 0
      for (const file of expiredFiles) {
        try {
          await client.delete(file.file_path)
          await file.destroy()
          deletedCount++
        } catch (error) {
          logger.warn(`Failed to cleanup file: ${file.id}`, error)
        }
      }

      logger.info(`Cleaned up ${deletedCount} expired files`)
      return deletedCount
    } catch (error) {
      logger.error('Cleanup expired files failed:', error)
      throw error
    }
  }

  /**
   * 验证文件类型
   * @param {string} mimetype - MIME类型
   * @returns {boolean} 是否支持
   */
  isFileTypeSupported(mimetype) {
    return !!SUPPORTED_FILE_TYPES[mimetype]
  }

  /**
   * 异步处理文件
   * @param {Object} fileRecord - 文件记录
   * @param {Buffer} fileBuffer - 文件内容
   */
  async processFileAsync(fileRecord, fileBuffer) {
    try {
      logger.info(`Starting file processing: ${fileRecord.id}`)
      
      // 处理文件，生成预览图和提取信息
      const processResult = await fileProcessingService.processFile(fileRecord, fileBuffer)
      
      // 更新文件记录
      await fileRecord.update({
        preview_url: processResult.previewUrl,
        page_count: processResult.pageCount
      })
      
      logger.info(`File processing completed: ${fileRecord.id}`, {
        previewUrl: processResult.previewUrl,
        pageCount: processResult.pageCount
      })
    } catch (error) {
      logger.error(`File processing failed: ${fileRecord.id}`, error)
      // 处理失败不影响文件上传，只记录错误
    }
  }

  /**
   * 重新处理文件
   * @param {number} fileId - 文件ID
   * @param {number} userId - 用户ID
   * @returns {Promise<Object>} 处理结果
   */
  async reprocessFile(fileId, userId) {
    try {
      const file = await File.findOne({
        where: {
          id: fileId,
          user_id: userId,
          status: 1
        }
      })

      if (!file) {
        throw new Error('文件不存在')
      }

      // 从OSS下载文件内容
      const result = await client.get(file.file_path)
      const fileBuffer = result.content

      // 重新处理文件
      const processResult = await fileProcessingService.processFile(file, fileBuffer)

      // 更新文件记录
      await file.update({
        preview_url: processResult.previewUrl,
        page_count: processResult.pageCount
      })

      logger.info(`File reprocessed successfully: ${fileId}`)

      return {
        id: file.id,
        previewUrl: processResult.previewUrl,
        pageCount: processResult.pageCount,
        metadata: processResult.metadata
      }
    } catch (error) {
      logger.error('Reprocess file failed:', error)
      throw error
    }
  }

  /**
   * 格式化文件大小
   * @param {number} bytes - 字节数
   * @returns {string} 格式化后的大小
   */
  formatFileSize(bytes) {
    if (bytes === 0) return '0 B'
    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
  }
}

module.exports = new FileService()